package net.bingosoft.common.struts;

import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.validator.Validator;
import org.apache.commons.validator.ValidatorException;
import org.apache.struts.Globals;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.util.RequestUtils;
import org.apache.struts.validator.BeanValidatorForm;
import org.apache.struts.validator.LazyValidatorForm;
import org.apache.struts.validator.Resources;

/**
 * 2008-4-14 下午04:04:24
 * Author:yangdongyu(yangdy@bingosoft.net)
 * ReadMe:Action 执行的上下文,可以通过该类获取HttpServletRequest,和HttpServletResponse对象
 * ChangeLog:
 */
public class ActionContext {
	private static final Log log = LogFactory.getLog(ActionContext.class);
	private static ThreadLocal<HttpServletRequest> requestHolder = new ThreadLocal<HttpServletRequest>();
	private static ThreadLocal<HttpServletResponse> responseHolder = new ThreadLocal<HttpServletResponse>();

	/**
	 * 获取当前Action执行相关的Request
	 * @return
	 */
	public static final HttpServletRequest getRequest(){
		return requestHolder.get();
	}
	/**
	 * 获取当前Action 执行相关的Response
	 * @return
	 */
	public static final HttpServletResponse getResponse(){
		return responseHolder.get();
	}
	/**
	 * 初始化ActionContext
	 * @param request
	 * @param response
	 */
	public static void init(HttpServletRequest request,HttpServletResponse response){
		requestHolder.set(request);
		responseHolder.set(response);
	}
	/**
	 * 销毁ActionContext 中保持的数据
	 */
	public static void destory(){
		requestHolder.set(null);
		responseHolder.set(null);
	}

	/**
	 * 实现页面转发
	 * @param pathName
	 * @throws ServletException
	 * @throws IOException
	 */
	public static final void forward(String pathName) throws ServletException, IOException{
		HttpServletRequest request = getRequest();
		HttpServletResponse response = getResponse();
		RequestDispatcher dispatcher = getRequest().getRequestDispatcher(pathName);
		dispatcher.forward(request,response);
	}

	/**
	 * 实现页面重定向
	 * @param pathName
	 * @throws IOException
	 */
	public static final void redirect(String pathName) throws IOException{
		getResponse().sendRedirect(pathName);
	}
	/**
	 * 将Request中的数据注入的指定类型的bean中
	 * @param <T>
	 * @param targetClass 待注入属性的Bean的类型
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws ServletException
	 */
	public static final <T> T fillBean(Class<T> targetClass) throws InstantiationException, IllegalAccessException, ServletException{
		T instance = targetClass.newInstance();
		RequestUtils.populate(instance,getRequest());
		return instance;

	}
	/**
	 * 将Request中的数据注入的指定的bean中
	 * @param <T>
	 * @param targetBean 待注入数据的bean
	 * @return
	 * @throws ServletException 
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws ServletException
	 */
	public static final <T> T fillBean(T targetBean) throws ServletException {
		RequestUtils.populate(targetBean,getRequest());
		return targetBean;
	}

	/**
	 * 从request中获取请求参数，并以Map的形式返回
	 * @param request
	 * @return
	 */
	public static Map<String,Object> getParameterMap() {
		HttpServletRequest request = getRequest();
		Enumeration names = request.getParameterNames();
		Map<String,Object> map = new HashMap<String,Object>();
		while (names.hasMoreElements()) {
			String name = (String) names.nextElement();
			String[] s = request.getParameterValues(name);
			if (s != null) {
				if (s.length > 1) {
					map.put(name, s);
				}else{
					map.put(name, s[0]);
				}
			}
		}
		return map;
	}
	/**
	 * 直接输出JSON对象.
	 */
	public static void renderJSON(String json) {
		render(json,"text/x-json;charset=UTF-8");
	}
	/**
	 * 直接输出纯字符串.
	 */
	public static void renderText(String text) {
		render(text,"text/plain;charset=UTF-8");
	}

	/**
	 * 直接输出纯HTML.
	 */
	public static void renderHtml(String html) {
		log.debug("输出的text/html的内容为: " + html);
		render(html,"text/html;charset=UTF-8");
	}

	/**
	 * 直接输出纯XML.
	 */
	public static void renderXML(String xml) {
		render(xml,"text/xml;charset=UTF-8");
	}
	/**
	 * 直接输出.
	 * 
	 * @param contentType 内容的类型.html,text,xml的值见后，json为"text/x-json;charset=UTF-8"
	 */
	public static void render(String text,String contentType){
		try {
			HttpServletResponse response = getResponse();
			response.setContentType(contentType);
			response.getWriter().write(text);
		} catch (IOException e) {
			log.error(e.getMessage(), e);
		}
	}
	/**
	 * 在request对象中取出int类型的参数值
	 * @param request
	 * @param param  参数名字
	 * @return 如果参数不存在或者不能转换为int类型则返回0，否则返回实际数值
	 */
	public static int getIntParam(String param) {
		int value = 0;
		try {
			value = Integer.parseInt(ActionContext.getRequest().getParameter(param).trim());
		} catch (Exception e) {
			log.debug(e);
		}
		return value;
	}
	/**
	 * 获取一个boolean类型的参数
	 * @param request
	 * @param param
	 * @return
	 */
	public static boolean getBooleanParam(String param){
		return Boolean.valueOf(getStringParam(param)).booleanValue();
	}

	/**
	 * 在request对象中取出int类型的参数值,如果出现异常，则返回默认值nDefaultVal
	 * @param request
	 * @param param  参数名字
	 * @return 如果参数不存在或者不能转换为int类型则返回0，否则返回实际数值
	 */
	protected int getIntParam( String param, int nDefaultVal) {
		int value = nDefaultVal;
		try {
			value = Integer.parseInt(ActionContext.getRequest().getParameter(param).trim());
		} catch (Exception e) {
			log.debug(e);
		}
		return value;
	}

	/**
	 * 在request对象中取出long类型的参数值
	 * @param request
	 * @param param 参数名字
	 * @return 如果参数不存在或者不能转换为long类型则返回0，否则返回实际数值
	 */
	public static long getLongParam( String param) {
		long value = 0;
		try {
			value = Long.parseLong(ActionContext.getRequest().getParameter(param));
		} catch (Exception e) {
			log.debug(e);
		}
		return value;
	}

	/**
	 * 在request对象中取出非null的字符串参数值
	 * @param request
	 * @param param
	 * @return 如果参数不存在返回""，否则返回实际字符串
	 */
	public static String getStringParam( String param) {
		String value = ActionContext.getRequest().getParameter(param);
		return (null == value) ?"": value ;
	}
	
	/**
	 * 在request对象中取出非null的字符串参数值,并将结果trim
	 * @param request
	 * @param param
	 * @return 如果参数不存在返回""，否则返回实际字符串
	 */
	public static String getTrimStringParam(String param) {
		String value = ActionContext.getRequest().getParameter(param);
		return (null == value) ?"": value.trim() ;
	}
	/**
	 * 从request对象中取出param指定的参数,如果不存在,返回defaultValue
	 * @param request
	 * @param param
	 * @param defaultValue
	 * @return
	 */
	public static String getStringParam(String param,String defaultValue){
		String value = ActionContext.getRequest().getParameter(param);
		return (null == value) ?defaultValue: value ;
	}
	/**
	 * 根据cookie名称获取对应的Cookie
	 * @param request
	 * @param cookieName
	 * @return
	 */
	public static Cookie getCookieByName(String cookieName){
		Cookie cookie = null;        
		Cookie[] cookies = ActionContext.getRequest().getCookies();
		if(null != cookies){
			for(int i=0;i<cookies.length;i++){
				if(cookies[i].getName().equalsIgnoreCase(cookieName)){
					cookie = cookies[i];
					break;
				}
			}
		}
		return cookie;
	}
	/**
	 * 绑定一个对象到Request中，该对象可以当作表单使用
	 * @param formKey 对象在Request中的键值
	 * @param bean 待保存的对象
	 */
	public static void bindForm(String formKey,Object bean){
		if(bean instanceof BeanValidatorForm){
			ActionContext.getRequest().setAttribute(formKey, bean);
		}else{
			ActionContext.getRequest().setAttribute(formKey, new BeanValidatorForm(bean));
		}
	}

	/**
	 * 绑定一个LazyValidatorForm对象到Request中
	 * @param formKey 对象在Request中的键值
	 */
	public static void bindLazyForm(String formKey){
		ActionContext.getRequest().setAttribute(formKey, new LazyValidatorForm());
	}


	/**
	 * 绑定一个对象到Session中，该对象可以当作表单使用
	 * @param formKey 对象在Request中的键值
	 * @param bean 待保存的对象
	 */
	public static void bindFormToSession(String formKey,Object bean){
		ActionContext.getRequest().getSession().setAttribute(formKey, new BeanValidatorForm(bean));
	}


	/**
	 * 弹出提示信息并重定向到指定路径
	 * @param prompt 提示信息
	 * @param path  返回路径
	 */
	public static void promptAndRedirect(String prompt,String path) {
		StringBuilder html = new StringBuilder("<script>");
		if(StringUtils.isNotEmpty(prompt)){
			html.append("alert('"+prompt+"');");
		}
		if(StringUtils.isNotEmpty(path)){
			html.append("window.location = '").append(getRequest().getContextPath()).append(path).append("';");
		}
		html.append("</script>");		
		renderHtml(html.toString());
	}
	
	/**
	 * 提示信息,并替换父页面
	 * @param msg
	 * @param url
	 */
	public static void promptAndRedirectParent(String msg,String url){
		StringBuilder sb = new StringBuilder();
		sb.append("<script>alert('").append(msg).append("');parent.window.location.href='").append(url).append("'</script>");
		renderHtml(sb.toString());
	}
	
	/**
	 * 弹出操作提示,关闭当前窗口并刷新当前窗口的父窗口
	 * @param msg 提示信息
	 * @param closeCurrent 
	 */
	public static void promptAndReloadParent(String msg,boolean closeCurrent) {
		StringBuilder sb = new StringBuilder();
		sb.append("<script>").append("alert('").append(msg).append("');try{window.opener.location.reload();}catch(e){}").append(closeCurrent ? "window.close();":"").append("</script>");
		renderHtml(sb.toString());
	}
	
	/**
	 * 提示信息,并异步刷新父窗口
	 * @param msg
	 */
	public static void promptAndQuery(String msg,boolean closeCurrent){
		StringBuilder sb = new StringBuilder();
		sb.append("<script>").append("alert('").append(msg).append("');window.opener.query();").append(closeCurrent ? "window.close();":"").append("</script>");
		renderHtml(sb.toString());
	}
	
	

	/**
	 * 向Request中放置属性
	 * @param key
	 * @param obj
	 */
	public static void setRequestAttribute(String key,Object obj){
		getRequest().setAttribute(key, obj);
	}

	/**
	 * 向Session中放置属性
	 * @param key
	 * @param obj
	 */
	public static void setSessionAttribute(String key,Object obj){
		getRequest().getSession().setAttribute(key, obj);
	}
	
	/**
	 * 向Session中放置属性
	 * @param key
	 * @param obj
	 */
	public static Object getSessionAttribute(String key){
		return getRequest().getSession().getAttribute(key);
	}
	

	/**
	 * 通过struts的验证插件实现对对象或者表单的验证
	 * @param validationKey 待验证对象或表单在验证配置文件中的键值
	 * @param bean 待验证的bean
	 * @return 验证是否成功
	 */
	public static boolean validate(String validationKey,Object bean){
		return validate(validationKey, bean, 0);
	}
	/**
	 * 通过struts的验证插件实现对对象或者表单的验证
	 * @param validationKey 待验证对象或表单在验证配置文件中的键值
	 * @param bean 待验证的bean
	 * @param page 当表单比较大的时候,我们可以对属性进行分页,然后验证,如果没有进行分页,该值应该为0
	 * @return 验证是否成功
	 */
	public static  boolean validate(String validationKey,Object bean,int page){
		HttpServletRequest request = getRequest();
		ServletContext application = request.getSession().getServletContext();
		ActionErrors errors = new ActionErrors();
		Validator validator = Resources.initValidator(validationKey,bean,application, request,errors, page);
		try {
			validator.validate();
		} catch (ValidatorException e) {
			log.error(e.getMessage(), e);
		}
		if ((errors == null) || errors.isEmpty()) {
			if (log.isTraceEnabled()) {
				log.trace("  No errors detected, accepting input");
			}
			return true;
		}else{
			request.setAttribute(Globals.ERROR_KEY, errors);
			return false;
		}
	}
	

}
